==================================================
TABLE OF CONTENTS
===============================================
1- Introduction
2- How Text is Normally Stored
3- Headers
4- Pointer Tables
5- Moving Text in SNES Roms
6- Physical Rom Expansion
7- Expanding text past its bank
8- Conclusion
========================================
SECTION 1 INTRODUCTION
=======================================================
1.0 General Stuff about this document
This document was created to help people who wish to learn about
pointer tables and SNES rom expansion. This document may be very
confusing but I tried to keep it as simple as possible! heh. I
wrote in in one night! So I'll probably have to update it later
to fix spelling errors, or make things easier to understand...
but I'm nothing more than a lazy bastard, so my hacks come first!
Anyways, if you do not know anything about rom-hacking, or you
don't know much about it, then LEARN and get some experience! the
only program you'll need to do the following is a hex editor. I
recommend "Hex Workshop"! I also tried to write this document to be as
universal as possible, so not every rom will be modified or
expanded in the following ways. So if you have problems with this
document, then you're either hacking an EVIL rom, or something I
haven't seen yet. Or I might not have gotten my point accross..
Please, tell me how good this document is! I beg you!
1.1 History
version 1.0 (HTML)
Ported to HTML by CataclysmX
==============================================
SECTION 2 HOW TEXT IS NORMALLY STORED
============================================
2.0 Variable Length Text
In rom's text is usually stored in clumps of text strings. For
instance, one text string will appear after another, and are
usually separated by a hex value which signifies the end of a
string (not a line break!). Now the text in these clumps of text
strings (I like to call them "text blocks") won't
nessessarily have the text in the order that it appears in the
game. In NES roms this is how all of the text is usually stored,
with a "standard pointer table system". But in SNES
roms, I have found other ways in which text is stored; Some times
text will be stored in text blocks as mentioned above, but will
include some coding in between each string instead of a standard
hex to signify the end of a line. These text blocks usually don't
have pointer tables and you should be able to change the lengths
of individual strings without any problems! The only downfall to
text stored like this is the fact that it makes it harder to dump
text from it to get it translated. Examples of text that's stored
like this are the Romancing Saga games.
2.1 Constant Length text
One other way that some text is sometimes stored in SNES roms is
in a "constant length" format. This is usually how
monster names, items, ect... are stored in RPGs. The Final
Fantasy games store that kind of stuff in that format. What
Constant Length text is; It's a bunch of text (items) that have a
certain length and are not separated by hex values which signify
the end of a string. They run right into one another... For
example, the Items in Final Fantasy 4 are 9 characters long, and
they follow one another like this:
Tent FenixDownPotion BlackSwrdIronArrow
as you can see there is no specific hex value separating them.
Which means that you can use the extra space as you wish! Because
if you look there are still 5 spaces to use for Tent, so you can
make that name even longer of you wish! While this may be good
news for some things, You wont be able to exceed the maximum
amount of spaces used for each item. The only way to increase the
amount of letters you can use for Constant Length text is to
learn ASM!
2.2 Text that's just floating around
And finally, sometimes in SNES roms, there is just text floating
around in the rom on its own, not in any specific "Text
Blocks". The only way to expand these out is to move'em to
somewhere in the rom where there is room to epand them out! (explained
in more detail later on... section 5)
2.3 Something else you should know about the way SNES stores
text.
Sometimes there are Text Blocks in the rom which do not use
pointer tables. These can just simply be expanded out as you wish
without any trouble just by moving the hex values which signify
the end of a string. This is similar to the "RS" text
blocks with the coding in between each string. just move the
coding to fit text into rom. But one thing you should know is
that there is sometimes text stored in the rom (in text blocks)
that have to be expanded out in a similar mannar that the text
floating around has to be. Basically this type of text is text
just "floating around" in the rom, exept they follow
one another like text would in a standard text block.
=======================================================
SECTION 3 HEADERS
============================================
3.0 NES Headers
The headers in NES roms are in the first line of an NES rom in a
hex editor. the fist 16 bytes of the rom is its header. In other
words the header covers "10" hex bytes. This is an
important number to remember when editing pointer tables in NES
roms.
the header usually looks something like this:
4E45 531A 1000 1300 0000 0000 0000 0000
You'll notice that the first three bytes are the ASCII standard
for "NES"! Other info is stored here such as the mapper
number, ect....
3.1 SNES Headers
The header in SNES roms is remarkably bigger than in NES roms. It
covers 512 bytes. Or "200" hex bytes. This is also
another important number to remember. Not as important for
pointer tables though, but it is important for moving text blocks
and stuff!
the header in an SNES rom looks similar to this:
8000000000000000AABB040000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
The information here is not really important.
But if you're rom does not have a header, then ADD ONE!
(This is sometime the cause of roms not working in some emulators)
To add a header to it, just copy a header from any SNES game that
has one, and then "Insert" the copied header into the
rom.
==========================================
SECTION 4 POINTER TABLES
=============================================
4.0 NES Pointer Tables
To find a pointer table for the text in your rom, it is
nessessary that you know where the text is in the rom, what hex
signifies the end of a line, and by knowing these you can then
find the beginning of the text block. Once you find the beginning
of the text block the pointer table should be IMMEDIATELY before
the text! It will look like it has a pattern to it. Figuring out
the pattern is mostly up to you, but here is pretty much how you
figure out how it works. Take an address from the beginning of a
line. (An example would be 012D63) and knock off the all extra
letters except for the last 4 digits making it 2D63. Pointer
tables store addresses in pairs so 2 hex values are needed...
break up 2D63 into pairs and you got 2 hex values.. 2D, and 63!
Now before you break up the hex values, you gotta subtract the
header from the address. Since the NES header is 10 hex bytes,
subtract 2D63 by 10 making it 2D53. Now break this up into pairs
making it 2D 53, and then re-arrange it backwards! (thats how
roms store addresses. so 2D 53, becomes 53 2D. This will tell you
one of the hex values in each pointer in the pointer tables. You
should be able to find 53 in there, but 2D might be something
else.. So you're actually looking for 53xx (where xx is unknown).
That's up to you to figure out!
an example of a pointer table followed by text in an NES rom:
019D30: 4D76 00F8 349D 3B9D 419D 449D 499D 4D9D
019D40: 529D 569D E5E3 F6CD 4ADA 70F8 F9FA FBF0
019D50: 704C FE70 4BDD CEF3 705C F64D 704C F6CF
019D60: CE70 F5DD CB70 4BF0 DDF1 F2DD F370 83B7
Explanation: Well, hex "70" signifies the end of a
string so using that you find the begining of the text block
which is at hex 019D44, and so everything before that is the
pointer table! You'll notice that 9D repeats alot in the pointer
table. Well, that is your unknown which you gotta figure out on
your own!
4.1 SNES Pointer Tables
SNES pointer tables work in the same manner, except you don't
subtract the header from it. But you gotta watch out, because
sometimes you might get an evil rom in which you GOTTA subtract
something, but thats very rare and easy to deal with once you get
the hang of it! Now also keep in mind that sometimes text in SNES
roms don't use a pointer table(Romancing SaGA). So if you can't
find one before the text, then just experiment! Try changing the
lengths of the strings by moving around the hex that signifies
the end of a string and see if it works! But if it doesn't work,
and there's no pointer table, then you're gonna have to learn how
to move text within the rom! (explained in section 5)
================================ SECTION 5 MOVING TEXT IN SNES
ROMS ==============================================
5.0 Moving Text Within Banks
Now this is more heavy stuff! You might have to do this if the
text you have doesn't have a pointer table, and wont expand just
by moving the hex to signify the end of a text string. You will
also have to do this to expand text that's just floating around
in the rom. Most of the time this text is moved within Banks.
What's a bank? well... time for my explanation. A bank is a part
of the rom in which info is stored. One bank in a low-rom is 32KB
(8000 hex bytes) and in a high-rom its 64KB (10000 hex bytes).
For instince, the adress $000200 to $0081FF is the first bank
within a low-rom and $008200 to $0101FF is the 2nd bank, ect...
And in a high-rom $000200 to $0101FF is the first bank and $020200
to $0301FF is the 2nd bank, ect... These addresses have the $200
header included if you notice! Oh, and did I forget to mention,
the "$" before the address signifies that I'm talking
about hex values! Anyways... Most of the time text that's just
floating there, or whatever can only be moved within the bank
that it's located in. To do this you gotta start converting the
address into a pointer to that address you can find! First, lets
take some text from FF4 that's on its own (not in any specific
text block) at the address 09DEC6. Now subtract the header from
this address ($200 in SNES roms, if the game has a header). So $09DEC6
- $200 = $09DCC6. Now, since you are just moving one small thing,
chances are, it can only be moved within that bank! Which means
that it has to be moved within $098000 to $09FFFF (without the
header, ofcourse. also note that FF4 is a low-rom). Now the next
step to do is to get rid of the 09 before the rest of the address,
since jumps within banks are stored as 2 hex bytes. So 09DCC6
becomes DCC6. Now split it up and make it backwards so it becomes
C6DC, and search for that number within the bank, and hopefully
you'll find the pointer!
Another Note: The address you are searching for must always be
between 8000 to FFFF in a low-rom, so if you're looking up a
pointer for text at 0928B0, subtract the header, knock off the
extra 09 (or whatever that may be), which makes it 26B0. Now
before you split it up and make it backwards, you gotta att $8000
to it, to make the address between 8000 to FFFF, so $26B0 + $8000
becomes $A6B0. You then re-arrange it as B0A6 and search for that!
But in a high-rom, the address can be anywhere between 0000 and
FFFF since the banks are 64KB instead of 32KB.
5.1 Moving Large Text Blocks (and other stuff) To Different
Banks!
Usually Large Blocks of text will have pointers that will anable
you to move text to anywhere in the rom! This is where physical
expansion comes in handy! (explained in section 6) What you will
have to do is move text to a place where there is enough room to
expand it out. First find the place where your text begins. (you'll
have to move text and its pointer tables seperately... This may
also apply for some text just floating in the rom, but they
usally use pointers within banks to point to them.) Moving these
is basically done in the same mannor as above, exept you gotta
figure out what bank its in. The first thing to do is subtract
the header, and this following chart shows the conversion between
the actual address and the way the SNES will read the address.
this chart is for low-roms:
HEX |
Low-ROM SNES |
|
---|---|---|
000000-007FFF |
= |
008000-00FFFF |
I'm sure you see the pattern now. So lets say you have a text
block located at $080600. Subtract the header, so it becomes $080400,
and then look it up on the chart and find its new address. so $080400
is actually $108400. Now split it up into pairs -> 10 84 00,
and re-arrange them backwards -> 008410. Now you'll have to
search for that, and remember, it might appear more than once in
the rom, so the best thing to do change all of these addresses
that appear in the rom to the new one.
A little hint: These kind of just USUALLY have "BF"
before them, so 008410, might look like BF008410.
Now for high-roms since the banks are in 64KB blocks the way the
snes addresses them is different. They don't have to be between
the 8000-FFFF crap! It just adds up like a normal adress exept it
starts at C00000. So really, all you gotta do is add $C00000 to
the hex address to get the High-rom SNES address. For example,
take hex $1AE380, subtract the header so it becomes $1AE180 and
now add $C00000 so it becomes $DAE180. And there you go! You got
yourself your pointer!
===================================================
SECTION 6 PHYSICAL SNES ROM EXPANSION
===============================================
Now for the easy part! In SNES roms, all you gotta do to make the
rom bigger, is just add more space to it! Of course the space
that you add HAS to be a multiple of 32KB, or $8000 hex bytes, or
1 bank.
But the roms are usually more stable if you keep them at a
muliple of 4mbits.
below is a small chart which shows stable file sizes to keep your
rom at:
(the following hex addresses include the $200 header)
MBITs |
HEX BYTES |
~ SIZE |
---|---|---|
4mbit |
$080200 |
0.5MB |
yada yada yada... I'm
sure you see the pattern...
well, that about does it! Don't ask me how to expand NES roms,
because I don't know how, and from what I hear it's next to
impossible!
================================================
SECTION 7 EXPANDING TEXT PAST ITS BANK
=============================================
What do I have to say about this? Well, unless you're prepared to
do some ASM modifications, don't expand text past the bank that
its in. What I mean by this is, if you have a low rom and you're
expanding text, you can't have it exceed the 32KB that's
allocated for the bank, or 64KB for high-roms. What tends to
happen is the text that runs spills into the next bank tends not
to be displayed on the screen. Now I'm not sure that this is the
case with some roms, but I'm suspecting that it is because this
has happened to us in our FF4 translation. Now there is another
way to get around the problem, and that's to limit the player to
using ZSNES 2.95 because of a bug in it! But I would not
recommend using that as an alternative, because not everyone will
want to use that old version of ZSNES.
===============================================
SECTION 8 CONCLUSION
====================================
Wow! I wrote all this in one night!?! Yep! Now I'm damn tired!
Anyways, Most of the stuff in this document covers stuff on SNES
roms, so if you're having trouble with NES roms, please don't
contact me, because I probably won't know about it! I only know
how to find NES pointer tables, and that's it! But SNES is a
different story! I am constantly learning more and more, and so
someday this document will probably be even better! But for now,
it remains as it is.
I would like to thank the following people:
P-Funk: |
For helping me out with moving stuff within a rom |
Dark Force: |
For helping me out with some technical stuff as well |
Necrosaro: |
For creating his program to save time on adding up all of FF4's pointers!! (that would have taken a loooong time without him!) |
CataclysmX: |
For originally porting this document into HTML and other stuff! |
Any questions/comments? Send
away to AnusP!
Any HTML comments or flames Send
away to CaTaclysmX!
***Copyright Issues***
Anyone who distributes this file must not modify it in any way,
without prior consent from the author. They must also have a link
to J2E translations and Anus P's home page at the top or bottom
of the page. Thank you for your cooperation.
J2E Translations! (http://www.members.aol.com/j2etrans/index.html)
Anus P. (C) 1998